class Int {
    value;
    MAX_VALUE = 0x7fffffff;
    MIN_VALUE = -0x80000000;

    constructor(i) {
        i = parseInt(i)
        if (isNaN(i)) {
            throw new Error("只能是数字")
        }
        this.value = this.f(i)
    }

    f(i) {
        return i & this.MAX_VALUE;
    }

    valueOf() {
        return this.value;
    }
}

export default class Encryption {
    RAW_KEY;

    HASH_KEY;

    OFFSET = 0X20020724;

    BOOK = this.getF(2449) + "";

    constructor(key) {
        if (typeof key === 'string' && key) {
            key = key.toLowerCase();
            this.HASH_KEY = this.getHash(key);
            this.RAW_KEY = key;
        } else {
            throw new Error("key只能是字符串")
        }
    }

    getKey() {
        return this.RAW_KEY;
    }

    encrypt(text) {
        let chars = text.split("")
        for (let i = 0; i < chars.length; i++) {
            chars[i] = new Int(new Int(chars[i].charCodeAt(0)) + new Int(this.HASH_KEY) + this.getHash(i)).valueOf()
        }
        let arr = []
        for (let i = 0, len = chars.length; i < len; i += 3) {
            arr.push(String.fromCharCode(...(chars.slice(i, i + 3))));
        }
        return arr.join("");
    }

    decrypt(data) {
        if (typeof data === 'string') {
            return this.decryptString(data)
        }
        console.warn("无法进行解密的类型", data)
        return data
    }


    getHash(i) {
        if (typeof i === 'number') {
            if (i < 0) {
                i = -i;
            }
            let c = parseInt(this.BOOK.charAt(i % 512));
            return new Int((i * i + c * c) + this.OFFSET).valueOf();
        } else {
            let value = i.split("")
            let h = new Int(0);
            for (let c of value) {
                h = new Int(new Int(31 * h) + new Int(c.charCodeAt(0))).valueOf()
            }
            return h.valueOf();
        }

    }

    getF(i) {
        if (i < 3) {
            return "1";
        }

        let arr = [BigInt(1), BigInt(1)]
        let sum = BigInt(0)
        for (let j = 0; j < i - 2; j++) {
            let n = arr[1];
            arr[1] = arr[0] + arr[1]
            arr[0] = n;
            sum += arr[1]
        }
        return sum.toString();
    }

    decryptString(text) {
        let chars = text.split("")
        for (let i = 0, l = chars.length; i < l; i++) {
            chars[i] = new Int(new Int(chars[i].charCodeAt(0)).valueOf() - new Int(this.HASH_KEY).valueOf() - this.getHash(i).valueOf()).valueOf()
        }
        let arr = []
        for (let i = 0, len = chars.length; i < len; i += 3) {
            arr.push(String.fromCharCode(...(chars.slice(i, i + 3))));
        }
        return arr.join("");
    }
}